#include <stdio.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/wait.h>
#include <signal.h>

#define LISTEN_SZ 10
void do_sigchild(int sig) {
    //通过signal的方式
    wait(NULL);
}

void do_process_client(int cfd) {
    char buffer[1024] = {0};
    ssize_t rbytes, sbytes;
    for (;;) {
        rbytes = recv(cfd, buffer, sizeof(buffer), 0);

        if (rbytes == -1) {
            perror("recv error");
            exit(EXIT_FAILURE);
        } else if (rbytes == 0 ) {
            printf("client quit\n");
            close(cfd);
            break;
        } else if (rbytes > 0) {
            printf("recv msg: %s\n", buffer);
            // 发送回客户端
            sbytes = send(cfd, buffer, rbytes, 0);
            if (sbytes == -1) {
                perror("send error");
                exit(EXIT_FAILURE);
            }
        }

    }
    close(cfd);
    exit(EXIT_SUCCESS);

}
//基于多进程实现并发服务器
int main(int argc, char const *argv[])
{
    struct sockaddr_in svr_addr, cli_addr;
    int sfd, cfd;
    int ret;
    sfd = socket(AF_INET, SOCK_STREAM, 0);
    pid_t pid;

    bzero(&svr_addr, sizeof(svr_addr));
    svr_addr.sin_family = AF_INET;
    svr_addr.sin_port = htons(atoi(argv[2]));
    svr_addr.sin_addr.s_addr = inet_addr(argv[1]);

    ret = bind(sfd, (struct sockaddr *)&svr_addr, sizeof(svr_addr));
    if (ret == -1) {
        perror("bind error");
        exit(EXIT_FAILURE);
    }

    ret = listen(sfd, LISTEN_SZ);
    if (ret  == -1) {
        perror("listen error");
        exit(EXIT_FAILURE);
    }
    // 当服务器与客户端建立连接之后， 会创建进程
    for(;;) {
        bzero(&cli_addr, sizeof(cli_addr));
        socklen_t len = sizeof(cli_addr);
        cfd = accept(sfd, (struct sockaddr *)&cli_addr, &len);
        if (cfd == -1) {
            perror("accept error");
            exit(EXIT_FAILURE);
        }
        printf("client ip: %s, port: %d\n", inet_ntoa(cli_addr.sin_addr), ntohs(cli_addr.sin_port));
        sighandler_t sigret;
        sigret = signal(SIGCHLD, do_sigchild);
        pid = fork();
        if (pid == -1) {
            perror("fork error");
            close(cfd);
        } else if (pid == 0) {
            //子进程处理与客户端的交互
            do_process_client(cfd); // 子进程结束之后会向父进程发送一个SIGCHILD 信号， 父进程默认忽略，导致子进程会进入僵死状态， 
        } 
    }
    close(sfd);
    return 0;
}
